/**
 * GeoSOA/util/ArrayList.js
 *
 * ArrayList object
 *
 * Inspired from Salvatore Vetro's ArrayList class at The Code Project: 
 * http://www.codeproject.com/KB/scripting/Observer_Pattern_JS.aspx
 *
 * Copyright (C) 2009 GeoSOA Research Group, Universite Laval
 * See LICENSE file under this distribution for licensing information
 * 
 * @author Etienne Dube
 * @since 20090329
 **/

dojo.provide("GeoSOA.util.ArrayList");


/**
 * The ArrayList object offers a list based on an array
 * 
 * @constructor
 */
GeoSOA.util.ArrayList = function () {
	this._list = [];
};


/**
 * Returns the number of elements in the list
 * 
 * @return Number of elements
 * @type Number
 */
GeoSOA.util.ArrayList.prototype.count = function () {
	return this._list.length;
};


/**
 * Adds an element at the end of the list
 * 
 * @param {Any} obj Element to add
 * @return ??
 * @type ??
 */
GeoSOA.util.ArrayList.prototype.add = function (obj) {
	return this._list.push(obj);
};


/**
 * Returns the element located at position idx
 * 
 * @param {Number} idx Index (position) of the element to retrieve (starts at 0)
 * @return The element at position idx
 * @type Any
 */
GeoSOA.util.ArrayList.prototype.getAt = function (idx) {
	if (idx >= 0 && idx < this._list.length) {
		return this._list[idx];
	}
	else {
		return undefined;
	}
};


/**
 * Clears the list of all contained elements
 */
GeoSOA.util.ArrayList.prototype.clear = function () {
	this._list = [];
};


/**
 * Removes the element located at position idx. All elements after it will be
 * shifted one position down.
 * 
 * @param {Number} idx Index (position) of the element to remove
 */
GeoSOA.util.ArrayList.prototype.removeAt = function (idx) {
	var m_count = this._list.length;
	
	if (m_count > 0 && idx >= 0 && idx < this._list.length) {
		switch(idx) {
		case 0:
			this._list.shift();
			break;
		case m_count - 1:
			this._list.pop();
			break;
		default:
			var head = this._list.slice(0, idx);
			var tail = this._list.slice(idx + 1);
			this._list = head.concat(tail);
			break;
		}
	}
};


/**
 * Inserts an element at position idx. All elements after it will be shifted
 * one position up.
 * 
 * @param {Any} obj Element to insert
 * @param {Number} idx Index (position) at which the element will be inserted
 * @return The position at which the element was inserted (-1 if failed, i.e.
 * the index is out of bounds)
 * @type Number
 */
GeoSOA.util.ArrayList.prototype.insert = function (obj, idx) {
	var m_count = this._list.length;
	var m_retval = -1;
	
	if (idx >= 0 && idx <= m_count) {
		switch(idx) {
		case 0:
			this._list.unshift(obj);
			m_retval = 0;
			break;
		case m_count:
			this._list.push(obj);
			m_retval = m_count;
			break;
		default:
			var head = this._list.slice(0, idx - 1);
			var tail = this._list.slice(idx);
			this._list = this._list.concat(tail.unshift(obj));
			m_retval = idx;
			break;
		}
	}
	
	return m_retval;
};


/**
 * Retrieve the 1st index (position) at which the obj element is found
 * 
 * @param {Any} obj Element to search
 * @param {Number} startIdx Index (position from 0) at which to start the search
 * @return The index of the found element, or -1 if not found
 * @type Number
 */
GeoSOA.util.ArrayList.prototype.indexOf = function (obj, startIdx) {
	var m_count = this._list.length;
	var m_retval = -1;
	
	if (startIdx >= 0 && startIdx < m_count) {
		var i = startIdx;
		
		while (i < m_count) {
			if (this._list[i] == obj) { // === ?
				m_retval = i;
				break;
			}
			i++;
		}
	}
	
	return m_retval;
};


/**
 * Retrieve the last index (position) at which the obj element is found
 * 
 * @param {Any} obj Element to search
 * @param {Number} startIdx Index (position from 0) at which to start the search
 * @return The index of the found element, or -1 if not found
 * @type Number
 */
GeoSOA.util.ArrayList.prototype.lastIndexOf = function (obj, startIdx) {
	var m_count = this._list.length;
	var m_retval = -1;
	
	if (startIdx >= 0 && startIdx < m_count) {
		var i = m_count - 1;
		
		while (i >= startIdx) {
			if (this._list[i] == obj) {
				m_retval = i;
				break;
			}
			i--;
		}
	}
	
	return m_retval;
};

